#pragma once
#include <thread>
#include <unordered_map>
#include "function_traits.h"
#include "funcbase.h"
#include "caller.h"

namespace KRPC {

template<typename ... Args>
class Subcribe : public FuncBase
{	
public:
	Subcribe(std::string topic, COM &com, int timeoutMsec) : \
		FuncBase(com), name(std::move(topic)), msec(timeoutMsec) 
	{
		assert(name.size() < MAX_RPCNAME_LEN);
	}
	
	void run(std::function<void(Args...)> deal)
	{
		send(name, RPC_SUB);
		while (1) {
			Packet &&packet = receive(msec);
			if (packet.valid()) {
				send(name, RPC_SUB);	//收到消息时立即回复一次避免服务端超时关闭订阅的连接
				call(deal, packet);
			} else {	//说明接收超时
				std::this_thread::sleep_for(std::chrono::milliseconds(100));//sleep 100ms,不然如果服务端不在则receive会立马返回造成cpu占用过高
				send(name, RPC_SUB);	//未收到消息发送一次再次请求订阅
			}
		}
	}
private:
	std::string name;
	int msec;	//接收超时秒数
};

template<>
class Subcribe<void> 
{	//禁止订阅void类型数据
};

class MultiSubcribe : public FuncBase
{	
public:
	MultiSubcribe(COM &com, int timeoutMsec) : FuncBase(com),  msec(timeoutMsec) {}

	template<typename F>
	void subcribe(std::string topic, F &&func)
	{
		assert(functions.find(topic) == functions.end());
		functions.emplace(std::move(topic), std::bind(Caller<decay_t<F>>(), 
			wrapper(std::forward<F>(func)), std::placeholders::_1));
	}

	template<typename F, typename Self>
	void subcribe(std::string topic, F &&func, Self *self)
	{
		assert(functions.find(topic) == functions.end());
		functions.emplace(std::move(topic), std::bind(Caller<decay_t<F>, Self>(), 
			wrapper(std::forward<F>(func)), self, std::placeholders::_1));
	}

	void run()
	{
		for (auto &it : functions) {
			send(it.first, RPC_SUB);
		}
		while (!functions.empty()) {
			Packet &&packet = receive(msec);
			if (!packet.valid()) {	//说明接收超时
				std::this_thread::sleep_for(std::chrono::milliseconds(100)); //sleep 100ms,不然如果服务端不在则receive会立马返回造成cpu占用过高
				for (auto &it : functions) {
					send(it.first, RPC_SUB);	//重新发送订阅信息
				}
				continue;
			}
				
			const MsgHead *h = packet.getHead();
			auto it = functions.find(h->name);
			if (h->mode == RPC_PUB && it != functions.end() && it->second(packet)) {
				send(it->first, RPC_SUB);
			} /*else {	//订阅回复的所有失败信息包括无权限,订阅类型不匹配等都默认删除订阅回调函数
				if (it != functions.end())
					functions.erase(it);
			} */
		}
	}

private:
	int msec;	//接收超时秒数
	std::unordered_map<std::string, std::function<bool(Packet &)>> functions;
};

} //end of namespace KRPC
